home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- * File: trails.c
- *
- * Usage: trails.c [-f] [-d] [-n devicenum] [-t title]
- * [-v videosource] [-I] [-h]
- *
- *
- * Description: Modification of simpleblend to use frame buffer connected to
- * blender output, and then fed back into blender background.
- * Simpleblend is an example of blending video with graphics. It
- * does not do any special setup, but it does show the output
- * in a graphics window and on video out. This program only
- * runs on video hardware that has a video output port.
- * This program will only run on the Galileo or IndyVideo board
- *
- * Functions: SGI Video Library functions used (see other modules)
- *
- * vlOpenVideo()
- * vlGetDeviceList()
- * vlGetNode()
- * vlCreatePath()
- * vlAddNode()
- * vlGetDevice()
- * vlSetupPaths()
- * vlSelectEvents()
- * vlRegisterHandler()
- * vlAddCallback()
- * vlSetControl()
- * vlGetControl()
- * vlMainLoop()
- * vlBeginTransfer()
- * vlEndTransfer()
- * vlDestroyPath()
- * vlCloseVideo()
- * vlGetErrno()
- * vlPerror()
- * vlStrError()
- *
- */
-
- #include <sys/types.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
-
- #include <X11/X.h>
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <Xm/MwmUtil.h>
-
- #include <vl/vl.h>
- #include <vl/dev_ev1.h>
-
- #include <gl/gl.h>
- #include <gl/device.h>
-
- /*
- * Function prototypes
- */
-
- void VideoTracking(Window, int,int);
- void processXEvent(uint, void *);
- void processVLEvent(VLServer, VLEvent *, void *);
- void docleanup(void);
- void usage(void);
-
- VLServer vlSvr = NULL;
- VLPath vlPath = -1;
- VLDevList devlist;
- VLNode src_vid;
- VLNode src_scr;
- VLNode drn_scr;
- VLNode drn_vid;
- VLNode drn_mem; /* memory drain (frame buffer) */
- VLNode mydev_node; /* device node to allow setting of sync mode */
- VLNode blend_node; /* 'cause blending controls are here */
-
- VLBuffer buffer;
- int imageCount = 1;
-
- Display *dpy;
- Window drnwin;
- int vin = VL_ANY;
- char *_progname;
- char *deviceName;
- int devicenum = -1;
- int ev1num = -1;
- int debug = 0;
-
- Atom WM_DELETE_WINDOW;
- Atom WM_PROTOCOLS;
-
- int lastw = 0, lasth = 0;
-
- #define Debug if (debug) printf
- #define fDebug if (debug) fprintf
-
- #define ESC_KEY '\006'
-
- #define USAGE \
- "%s: [-f] [-n <devicenum>] [-t] [-d] [-I] [-v <videonode> ] [-h]\n\
- \t-f\tdisable forking\n\
- \t-n n\tdevice number to use\n\
- \t-t\tset window title\n\
- \t-d\tdebug mode\n\
- \t-I\tprint node and path IDs for command line interface users\n\
- \t-v n\tvideo source node number n\n\
- \t-h\tthis help message\n"
-
- void
- usage()
- {
- fprintf(stderr, USAGE, _progname);
- }
-
- /* Constrain the window's aspect ratio */
- void
- constrainWindowResize(Display *dpy, Window win, int max_w, int max_h)
- {
- XSizeHints xsh;
-
- xsh.min_aspect.x = xsh.max_aspect.x = 80;
- xsh.min_aspect.y = xsh.max_aspect.y = 60;
- xsh.min_width = max_w;
- xsh.min_height = max_h;
- xsh.max_width = max_w;
- xsh.max_height = max_h;
- xsh.flags = PAspect|PMinSize|PMaxSize;
-
- XSetWMNormalHints(dpy, win, &xsh);
- XResizeWindow(dpy, win, max_w, max_h);
- }
-
- simplev2v()
- {
- VLServer svr;
- VLPath VIDPath;
- VLNode src, drn;
- int c;
- int devicenum = -1;
- char *_progName;
-
- /* Connect to the daemon */
- if (!(svr = vlOpenVideo("")))
- {
- printf("%s: can't open video: %s\n", _progName, vlStrError(vlGetErrno()));
- docleanup();
- }
-
- /* Set up a source node on the first available video device */
- src = vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY);
-
- /* Set up a video drain node on the first device that has one */
- drn = vlGetNode(svr, VL_DRN, VL_VIDEO, VL_ANY);
-
- /* Create a path using the selected device(s) */
- if (devicenum == -1)
- VIDPath = vlCreatePath(svr, VL_ANY, src, drn);
- else
- VIDPath = vlCreatePath(svr, devicenum, src, drn);
-
- /* Set up the hardware for and define the usage of the path */
- if (vlSetupPaths(svr, (VLPathList)&VIDPath, 1, VL_SHARE, VL_SHARE)<0)
- {
- printf("%s: can't setup path: %s\n", _progName, vlStrError(vlGetErrno()));
- docleanup();
- }
-
- /* Begin the data transfer */
- vlBeginTransfer(svr, VIDPath, 0, NULL);
-
- /* End the data transfer */
- vlEndTransfer(svr, VIDPath);
-
- /* Clean up and exit */
- vlDestroyPath(svr, VIDPath);
- vlCloseVideo(svr);
- }
-
- main(int argc, char **argv)
- {
- char *winname = NULL;
- int opterr = 0;
- int c,i;
- int dev;
- int ret;
- int nofork = 0;
- int x, y;
- int print_ids = 0;
- Atom WM_PROT_SET[2];
- Atom _SGI_VIDEO;
- VLControlValue val;
- int myret;
- VLTransferDescriptor xferDesc;
-
- _progname = argv[0];
-
- /*
- * Parse command line options
- * -f disable forking
- * -n n device number n
- * -d set debugging
- * -t set title
- * -v n use video input n
- * -I print node and path IDs
- * -h display help message
- */
- while ((c = getopt(argc, argv, "t:dv:In:fh")) != EOF)
- {
- switch(c)
- {
- case 'f':
- nofork = 1;
- break;
-
- case 'n':
- devicenum = atoi(optarg);
- break;
-
- case 'd':
- debug++;
- break;
-
- case 't':
- winname = optarg;
- break;
-
- case 'I':
- print_ids = 1;
- break;
-
- case 'v':
- vin = atoi(optarg);
- Debug("video input = %d\n", vin);
- break;
-
- case 'h':
- usage();
- exit(0);
- break;
- }
- }
-
- if (opterr)
- {
- usage();
- exit(1);
- }
-
- /* Run in background if no-forking option not set */
- if (!nofork)
- {
- ret = fork();
- switch (ret)
- {
- case 0:
- break;
-
- case -1:
- fprintf(stderr, "%s: can't fork\n");
- exit(1);
- break;
-
- default:
- exit(0);
- break;
- }
- }
-
- /* Connect to the daemon */
- if (!(vlSvr = vlOpenVideo("")))
- {
- printf("%s: opening video: %s\n",_progname,vlStrError(vlGetErrno()));
- exit(1);
- }
-
- /* Get the list of devices the daemon supports */
- if (vlGetDeviceList(vlSvr, &devlist) < 0)
- {
- printf("%s: getting device list: %s\n",_progname,vlStrError(vlGetErrno()));
- exit(1);
- }
-
-
- /* Make sure that the device the user requested (if any) is in the list */
- if ((devicenum >= (int)devlist.numDevices) || (devicenum < -1))
- {
- if (devlist.numDevices == 1)
- fprintf(stderr,"%s: The device number must be 0\n",_progname);
- else
- fprintf(stderr,"%s: The device number must be between 0 and %d\n",
- _progname, devlist.numDevices-1);
- exit(1);
- }
- /* find ev1 */
- for (i=0; i<devlist.numDevices; i++)
- if (strcmp(devlist.devices[i].name,"ev1") == 0)
- ev1num = i;
- if ( (ev1num == -1) /* no ev1 found ... OR ...*/
- || ((devicenum != -1) && (devicenum != ev1num))) /* non ev1 specified*/
- {
- printf("This program requires 'ev1' hardware.\a\n");
- if (ev1num != -1)
- printf("Use device number '%d', or use the default mode\n",ev1num);
- exit(1);
- }else
- {
- printf("Setting device number to %d\n", ev1num);
- devicenum = ev1num; /* allow default to work */
- }
-
-
- /*
- * Establish a path between the screen source and video
- * drain. Then add a video source node and a screen drain
- * node.
- */
-
- /* Setup drain nodes on the screen and video */
- drn_scr = vlGetNode(vlSvr, VL_DRN, VL_SCREEN, VL_ANY);
- Debug("drn_scr = %d\n", drn_scr);
- drn_vid = vlGetNode(vlSvr, VL_DRN, VL_VIDEO, VL_ANY);
- Debug("drn_vid = %d\n", drn_vid);
- /* Setup source nodes on the screen and video */
- src_scr = vlGetNode(vlSvr, VL_SRC, VL_SCREEN, VL_ANY);
- Debug("src_scr = %d\n", src_scr);
- src_vid = vlGetNode(vlSvr, VL_SRC, VL_VIDEO, vin);
- Debug("src_vid = %d\n", src_vid);
-
- /* Set up a drain node in memory (frame buffer) */
- drn_mem = vlGetNode(vlSvr, VL_DRN, VL_MEM, VL_ANY);
- Debug("drn_mem = %d\n", drn_mem);
-
- mydev_node = vlGetNode(vlSvr, VL_DEVICE, 0,0);
- Debug("mydev_node = %d\n", mydev_node);
- blend_node = vlGetNode(vlSvr, VL_INTERNAL, VL_BLENDER, VL_ANY);
- Debug("blend_node = %d\n", blend_node);
-
- vlPath = -1;
- /* If no device was specified... */
- if (devicenum == -1)
- {
- /* Try to create the screen to video path */
- vlPath = vlCreatePath(vlSvr, devicenum, src_scr, drn_vid);
- Debug("vlPath = %d\n", vlPath);
- /* Add the video source and screen drain nodes */
- ret = vlAddNode(vlSvr, vlPath, src_vid);
- Debug("vlAddNode(src_vid) returns %d\n", ret);
- if (!ret)
- ret = vlAddNode(vlSvr, vlPath, drn_scr);
- Debug("vlAddNode(drn_scr) returns %d\n", ret);
- if (ret)
- { /* Device doesn't support this path, these nodes */
- vlDestroyPath(vlSvr, vlPath);
- vlPath = -1;
- }
- else
- { /* Path OK, get device info */
- devicenum = vlGetDevice(vlSvr, vlPath);
- Debug("devicenum = %d\n", devicenum);
- deviceName = devlist.devices[devicenum].name;
- Debug("deviceName = %s\n", deviceName);
- }
- }
- else /* User specified a device */
- { /* Get the device info */
- deviceName = devlist.devices[devicenum].name;
- /* Try to create the screen to video path */
- vlPath = vlCreatePath(vlSvr, devicenum, src_scr, drn_vid);
- /* Add the video source and screen drain nodes */
- ret = vlAddNode(vlSvr, vlPath, src_vid);
- if (!ret)
- ret = vlAddNode(vlSvr, vlPath, drn_scr);
- if (ret)
- { /* Device doesn't support this path, these nodes */
- vlDestroyPath(vlSvr, vlPath);
- vlPath = -1;
- }
- }
- if (vlAddNode(vlSvr, vlPath, drn_mem))
- {
- vlPerror("Add memory drain Node");
- vlDestroyPath(vlSvr, vlPath);
- vlPath = -1;
- }
- Debug("vlAddNode(drn_mem)\n");
-
- if (vlAddNode(vlSvr, vlPath, mydev_node))
- {
- vlPerror("Add Device Node");
- vlDestroyPath(vlSvr, vlPath);
- vlPath = -1;
- }
- Debug("vlAddNode(mydev_node)\n");
-
- if (vlAddNode(vlSvr, vlPath, blend_node))
- {
- vlPerror("Add blend Node");
- vlDestroyPath(vlSvr, vlPath);
- vlPath = -1;
- }
- Debug("vlAddNode(blend_node)\n");
- if (vlPath == -1)
- { /* Couldn't create the path, quit */
- vlPerror("Path Setup");
- docleanup();
- }
-
- /* Print the node and path IDs for cmd line users */
- if (print_ids)
- {
- printf("SIMPLEBLEND NODE IDs:\n");
- printf("screen source = %d\n", src_scr);
- printf("video source = %d\n", src_vid);
- printf("screen drain = %d\n", drn_scr);
- printf("video drain = %d\n", drn_vid);
- printf("blend = %d\n", blend_node);
- printf("PATH ID = %d\n", vlPath);
- }
-
- /* Set up the hardware for and define the usage of the path */
- if (vlSetupPaths(vlSvr, (VLPathList)&vlPath, 1, VL_SHARE, VL_SHARE) < 0)
- {
- vlPerror("Error in device paths setup");
- printf("This program requires the device Sync to be in slave mode.\n");
- printf("Use the videopanel to set the device Sync to be slave.\n");
- exit(1);
- }
- Debug("vlSetupPaths()\n");
-
- printf("\nFor best results, use the blending controls provided\n");
- printf("by the program /usr/people/4Dgifts/examples/video/vl/keyctls.\n");
- printf("Interesting results can also be obtained by changing values\n");
- printf("in the Pro/Video Input and Pro/Video Output control panels of \n");
- printf("the videopanel.\n\n");
- printf("Type 'q' inside the video window to quit\n\n");
- /* Get the current size of the drain window */
- vlGetControl(vlSvr, vlPath, drn_scr, VL_SIZE, &val);
- lastw = val.xyVal.x;
- lasth = val.xyVal.y;
- /* Attempt to set the source to the same size */
- vlSetControl(vlSvr, vlPath, src_scr, VL_SIZE, &val);
- /* Make sure there's enough room for a source window of the same size */
- vlGetControl(vlSvr, vlPath, src_scr, VL_SIZE, &val);
-
- if (lastw != val.xyVal.x || lasth != val.xyVal.y)
- {
- printf("%s: unable to make two full size windows\n", _progname);
- docleanup();
- }
-
- /* Set the keyer mode, keyer source and blend controls */
- val.intVal = VL_EV1_KEYERMODE_LUMA;
- vlSetControl(vlSvr, vlPath, blend_node, VL_EV1_KEYER_MODE, &val);
- val.intVal = src_scr;
- vlSetControl(vlSvr, vlPath, blend_node, VL_EV1_KEYER_SOURCE, &val);
- /* val.intVal = src_scr; */
- val.intVal = src_vid;
- vlSetControl(vlSvr, vlPath, blend_node, VL_BLEND_A, &val);
-
- /* val.intVal = src_vid; */
- val.intVal = drn_mem;
- vlSetControl(vlSvr, vlPath, blend_node, VL_BLEND_B, &val);
-
- val.intVal = 7;
- vlSetControl(vlSvr,vlPath, blend_node, VL_EV1_KEYER_DETAIL, &val);
- val.intVal = 255;
- vlSetControl(vlSvr,vlPath, blend_node, VL_EV1_KEYER_FG_OPACITY, &val);
- val.intVal = 10;
- vlSetControl(vlSvr,vlPath, blend_node, VL_EV1_KEYER_VALUE_LUMA, &val);
- val.intVal = 10;
- vlSetControl(vlSvr,vlPath, blend_node, VL_EV1_KEYER_RANGE_LUMA, &val);
-
- /* Display the drain window */
- if (!(dpy = XOpenDisplay("")))
- {
- printf("%s: can't open display\n", _progname);
- docleanup();
- }
-
- drnwin = XCreateWindow(dpy, RootWindow(dpy, 0), 0, lasth, lastw, lasth, 0,
- CopyFromParent, CopyFromParent, CopyFromParent,
- (ulong) 0, NULL);
-
-
- _SGI_VIDEO = XInternAtom(dpy, "_SGI_VIDEO", False);
- WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
- WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
- WM_PROT_SET[0] = WM_DELETE_WINDOW;
- WM_PROT_SET[1] = _SGI_VIDEO;
- XSetWMProtocols(dpy,drnwin, WM_PROT_SET, 2);
-
- XStoreName(dpy, drnwin, "Video Trails");
-
- /* Adjust the drain window's aspect ratio */
- constrainWindowResize(dpy, drnwin, lastw, lasth);
-
- /* Set the video to appear in window drnwin */
- val.intVal = drnwin;
- vlSetControl(vlSvr, vlPath, drn_scr, VL_WINDOW, &val);
-
- /* Make sure there's room for both the source and drain window */
- vlGetControl(vlSvr, vlPath, drn_scr, VL_SIZE, &val);
- if (val.xyVal.x != lastw || val.xyVal.y != lasth)
- {
- printf("%s: Unable to setup two full size windows\n",_progname);
- docleanup();
- }
- vlGetControl(vlSvr, vlPath, src_scr, VL_SIZE, &val);
- if (val.xyVal.x != lastw || val.xyVal.y != lasth)
- {
- printf("%s: Unable to setup two full size windows\n",_progname);
- docleanup();
- }
-
- /* Get the location of the screen drain */
- vlGetControl(vlSvr, vlPath, drn_scr, VL_ORIGIN, &val);
- /* Move its window to that location */
- XMoveWindow(dpy, drnwin, val.xyVal.x, val.xyVal.y);
-
- XMapWindow(dpy, drnwin);
- XSelectInput(dpy, drnwin, KeyPressMask|VisibilityChangeMask
- |ExposureMask|StructureNotifyMask);
- XSync(dpy, 0);
-
- /* Specify a file descriptor and pending check function for VL events */
- vlRegisterHandler(vlSvr, ConnectionNumber(dpy), processXEvent,
- (VLPendingFunc)XPending, dpy);
-
- /* Set up event handler routine as callback for all events */
- vlAddCallback(vlSvr, vlPath, VLAllEventsMask, processVLEvent, NULL);
-
- /* Set the VL event mask so we only get control changed events */
- vlSelectEvents(vlSvr, vlPath, VLControlChangedMask);
-
- /* ### */
- /* Create and register a buffer of imageCount frames... */
- buffer = vlCreateBuffer(vlSvr, vlPath, drn_mem, imageCount);
- if (buffer == NULL)
- {
- vlPerror("trails");
- docleanup();
- }
- if (vlRegisterBuffer(vlSvr, vlPath, drn_mem, buffer))
- {
- vlPerror("trails");
- docleanup();
- }
-
- /*
- * Fill the transfer descriptor for a discrete transfer of imageCount
- * frames. If the external trigger option is set, we use VLDeviceEvent
- * for a trigger, otherwise trigger immediately. Note that this may not
- * work well on all devices, as VLDeviceEvent it not well-defined.
- */
- xferDesc.mode = VL_TRANSFER_MODE_DISCRETE;
- xferDesc.count = imageCount;
- xferDesc.delay = 0;
- xferDesc.trigger = VLTriggerImmediate;
-
- /* Start the data transfer immediately (i.e. don't wait for trigger) */
- myret = vlBeginTransfer(vlSvr, vlPath, 1, &xferDesc);
- Debug("vlBeginTransfer() = %d\n", myret);
-
- /* Handle event dispatching */
- vlMainLoop();
- }
-
- /*
- * VideoTracking - if the user changes the size of the window,
- * update the video to reflect the new size and position.
- */
- void
- VideoTracking(Window win, int x, int y)
- {
- Window dummyWin;
- VLControlValue val;
-
- /* Get X's idea of origin */
- XTranslateCoordinates(dpy, win, RootWindow(dpy, DefaultScreen(dpy)),
- 0, 0,
- &x, &y,
- &dummyWin);
-
- /* Try to make vl match X */
- val.xyVal.x = x;
- val.xyVal.y = y;
- if (win == drnwin)
- vlSetControl(vlSvr, vlPath, drn_scr, VL_ORIGIN, &val);
- else
- vlSetControl(vlSvr, vlPath, src_scr, VL_ORIGIN, &val);
- }
-
- /*
- * VLEvent processing for video to screen.
- * We only deal with control changed events.
- */
- void
- processVLEvent(VLServer vlSvr, VLEvent *ev, void *dummy)
- {
- VLControlChangedEvent *cev = (VLControlChangedEvent *) ev;
- VLControlValue val;
-
- Debug("VL event.type = %d\n", ev->reason);
- switch (ev->reason)
- { /* Ignore all but a change in the drain's location */
- case VLControlChanged:
- if ((cev->type == VL_ORIGIN)&&(cev->node == drn_scr))
- {
- /* Drain moved, move window accordingly */
- vlGetControl(vlSvr, vlPath, drn_scr, VL_ORIGIN, &val);
- XMoveWindow(dpy, drnwin, val.xyVal.x, val.xyVal.y);
- }
- break;
- }
- }
-
- /* XEvent processing for video to screen */
- void
- processXEvent(uint fd, void *source)
- {
- int i;
-
- if (source == (caddr_t)dpy)
- {
- XEvent ev;
-
- XNextEvent(dpy, &ev);
- switch (ev.type)
- {
- case ClientMessage:
- if (ev.xclient.message_type == WM_PROTOCOLS)
- if (ev.xclient.data.l[0] == WM_DELETE_WINDOW)
- docleanup();
- break;
-
- case Expose: /* These really don't effect us */
- case GraphicsExpose:
- case VisibilityNotify:
- break;
-
- case ConfigureNotify: /* Window moved or changed size */
- VideoTracking(ev.xany.window, ev.xconfigure.x,ev.xconfigure.y);
- break;
-
- case KeyPress:
- {
- XKeyEvent *kev = (XKeyEvent *)&ev;
- KeySym keysym;
- char buf[4];
-
- XLookupString(kev, buf, 1, &keysym, 0);
- switch (buf[0])
- {
- case '+':
- /* Quit */
- case 'q':
- case 'Q':
- case ESC_KEY:
- docleanup();
- break;
-
- default:
- break;
- }
- }
- }
- }
- }
-
- /* Dispose of the vl structures */
- void
- docleanup(void)
- { /* End the data transfer */
- vlEndTransfer(vlSvr, vlPath);
-
- /* Destroy the path, free it's memory */
- vlDestroyPath(vlSvr, vlPath);
-
- /* Disonnect from the daemon */
- vlCloseVideo(vlSvr);
-
- simplev2v(); /* make sure leave in 'nice' state */
- exit(0);
- }
-